#include "windowlistener.h"
#include "windowmanager.h"

#include <QDebug>

#ifdef Q_OS_WIN32
#include <windows.h>
#include <tlhelp32.h>
void GetProcessIdByName(const QStringList &nameList, QMap<QString, QList<DWORD>> &processMap)
{
    HANDLE hSnapshot = INVALID_HANDLE_VALUE;
    do
    {
        hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hSnapshot == INVALID_HANDLE_VALUE)
        {
            break;
        }

        PROCESSENTRY32 pe = { sizeof(pe) };
        for (BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe))
        {
            QString name = QString::fromWCharArray(pe.szExeFile).toLower();
            if (!nameList.contains(name))
            {
                continue;
            }
            processMap[name].append(pe.th32ProcessID);
        }
    }
    while (0);
    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hSnapshot);
    }
}

typedef struct EnumHWndsArg
{
    QMap<DWORD, QString> processMap;
    QList<WindowInfo> windowInfos;
} EnumHWndsArg, *LPEnumHWndsArg;

BOOL CALLBACK lpEnumFunc(HWND hwnd, LPARAM lParam)
{
    EnumHWndsArg *pArg = (LPEnumHWndsArg)lParam;
    DWORD processId;
    GetWindowThreadProcessId(hwnd, &processId);
    if (pArg->processMap.contains(processId))
    {
        TCHAR windowTitle[256] = { 0 };
        if (GetWindowText(hwnd, windowTitle, 256) && IsWindowVisible(hwnd))
        {
            WindowInfo windowInfo;
            windowInfo.setWindowId(hwnd);
            windowInfo.setWindowTitle(QString::fromWCharArray(windowTitle));
            windowInfo.setProcessId(processId);
            windowInfo.setProcessName(pArg->processMap[processId]);
            pArg->windowInfos.append(windowInfo);
        }
    }
    return TRUE;
}

void WindowListener::slotEnumWindows()
{
    QStringList processList = m_pWindowManager->processList();
    if (processList.isEmpty())
    {
        return;
    }

    // 根据进程名，获取进程id（一个进程名可能存在多个进程id）
    QMap<QString, QList<DWORD>> processMap;
    GetProcessIdByName(processList, processMap);
    if (processMap.isEmpty())
    {
        return;
    }

    QMap<DWORD, QString> pm;
    QMap<QString, QList<DWORD>>::const_iterator it;
    for (it = processMap.cbegin(); it != processMap.cend(); ++it)
    {
        QString name = it.key();
        QList<DWORD> tmp = it.value();
        for (int i = 0; i < tmp.count(); i++)
        {
            pm.insert(tmp[i], name);
        }
    }

    // 根据进程id，获取进程窗口句柄
    EnumHWndsArg wi;
    wi.processMap = pm;
    EnumWindows(lpEnumFunc, (LPARAM)&wi);
    if (wi.windowInfos.isEmpty())
    {
        return;
    }

    emit m_pWindowManager->onEnumWindows(wi.windowInfos);
}

#endif

#ifdef Q_OS_LINUX

// x11
void WindowListener::slotEnumWindows()
{

}
#endif

WindowListener::WindowListener(WindowManager *manager)
    : m_pWindowManager(manager)
{

}

WindowListener::~WindowListener()
{

}
